#include <asm-xen/xen-public/dom0_ops.h>
#include <asm-xen/linux-public/suspend.h>
#include <asm-xen/queues.h>
+#include <asm-xen/xenbus.h>
void machine_restart(char * __unused)
{
time_suspend();
+ xenbus_suspend();
+
ctrl_if_suspend();
irq_suspend();
ctrl_if_resume();
+ xenbus_resume();
+
time_resume();
blkdev_resume();
#include <linux/err.h>
#include "xenbus_comms.h"
+static unsigned int xb_irq;
+
#define RINGBUF_DATASIZE ((PAGE_SIZE / 2) - sizeof(struct ringbuf_head))
struct ringbuf_head
{
return 0;
}
-/* Set up interrpt handler off store event channel. */
+/* Set up interrupt handler off store event channel. */
int xb_init_comms(void)
{
- int err, irq;
+ int err;
+
+ if (!xen_start_info.store_evtchn)
+ return 0;
- irq = bind_evtchn_to_irq(xen_start_info.store_evtchn);
+ xb_irq = bind_evtchn_to_irq(xen_start_info.store_evtchn);
- err = request_irq(irq, wake_waiting, SA_SHIRQ, "xenbus", &xb_waitq);
+ err = request_irq(xb_irq, wake_waiting, 0, "xenbus", &xb_waitq);
if (err) {
printk(KERN_ERR "XENBUS request irq failed %i\n", err);
unbind_evtchn_from_irq(xen_start_info.store_evtchn);
return 0;
}
+
+void xb_suspend_comms(void)
+{
+
+ if (!xen_start_info.store_evtchn)
+ return;
+
+ free_irq(xb_irq, &xb_waitq);
+ unbind_evtchn_from_irq(xen_start_info.store_evtchn);
+}
#define _XENBUS_COMMS_H
int xs_init(void);
int xb_init_comms(void);
+void xb_suspend_comms(void);
/* Low level routines. */
int xb_write(const void *data, unsigned len);
.callback = dev_changed,
};
+void xenbus_suspend(void)
+{
+ /* We keep lock, so no comms can happen as page moves. */
+ down(&xenbus_lock);
+ xb_suspend_comms();
+}
+
+void xenbus_resume(void)
+{
+ xb_init_comms();
+ up(&xenbus_lock);
+}
+
/* called from a thread in privcmd/privcmd.c */
int do_xenbus_probe(void *unused)
{
int register_xenbus_watch(struct xenbus_watch *watch);
void unregister_xenbus_watch(struct xenbus_watch *watch);
+/* Called from xen core code. */
+void xenbus_suspend(void);
+void xenbus_resume(void);
+
#endif /* _ASM_XEN_XENBUS_H */
* @parm fd the file descriptor to restore a domain from
* @parm dom the id of the domain
* @parm nr_pfns the number of pages
+ * @parm store_evtchn the store event channel for this domain to use
+ * @parm store_mfn returned with the mfn of the store page
* @return 0 on success, -1 on failure
*/
-int xc_linux_restore(int xc_handle, int io_fd, u32 dom, unsigned long nr_pfns);
+int xc_linux_restore(int xc_handle, int io_fd, u32 dom, unsigned long nr_pfns,
+ unsigned int store_evtchn, unsigned long *store_mfn);
int xc_linux_build(int xc_handle,
u32 domid,
return r;
}
-int xc_linux_restore(int xc_handle, int io_fd, u32 dom, unsigned long nr_pfns)
+int xc_linux_restore(int xc_handle, int io_fd, u32 dom, unsigned long nr_pfns,
+ unsigned int store_evtchn, unsigned long *store_mfn)
{
dom0_op_t op;
int rc = 1, i, n, k;
}
ctxt.user_regs.esi = mfn = pfn_to_mfn_table[pfn];
p_srec = xc_map_foreign_range(
- xc_handle, dom, PAGE_SIZE, PROT_WRITE, mfn);
+ xc_handle, dom, PAGE_SIZE, PROT_READ | PROT_WRITE, mfn);
p_srec->resume_info.nr_pages = nr_pfns;
p_srec->resume_info.shared_info = shared_info_frame << PAGE_SHIFT;
p_srec->resume_info.flags = 0;
+ *store_mfn = p_srec->resume_info.store_mfn =
+ pfn_to_mfn_table[p_srec->resume_info.store_mfn];
+ p_srec->resume_info.store_evtchn = store_evtchn;
munmap(p_srec, PAGE_SIZE);
/* Uncanonicalise each GDT frame number. */
#define DEBUG 0
#if 1
-#define ERR(_f, _a...) fprintf ( stderr, _f , ## _a )
+#define ERR(_f, _a...) do { fprintf(stderr, _f , ## _a); fflush(stderr); } while (0)
#else
#define ERR(_f, _a...) ((void)0)
#endif
goto out;
}
+ /* Map the suspend-record MFN to pin it. The page must be owned by
+ dom for this to succeed. */
+ p_srec = xc_map_foreign_range(xc_handle, dom,
+ sizeof(*p_srec), PROT_READ | PROT_WRITE,
+ ctxt.user_regs.esi);
+ if (!p_srec){
+ ERR("Couldn't map suspend record");
+ goto out;
+ }
+
+ /* Canonicalize store mfn. */
+ if ( !translate_mfn_to_pfn(&p_srec->resume_info.store_mfn) ) {
+ ERR("Store frame is not in range of pseudophys map");
+ goto out;
+ }
+
print_stats( xc_handle, dom, 0, &stats, 0 );
/* Now write out each data page, canonicalising page tables as we go... */
}
}
- /* Map the suspend-record MFN to pin it. The page must be owned by
- dom for this to succeed. */
- p_srec = xc_map_foreign_range(xc_handle, dom,
- sizeof(*p_srec), PROT_READ,
- ctxt.user_regs.esi);
- if (!p_srec){
- ERR("Couldn't map suspend record");
- goto out;
- }
-
if (nr_pfns != p_srec->nr_pfns )
{
ERR("Suspend record nr_pfns unexpected (%ld != %ld)",
import errno
import os
+import re
import select
import sxp
from string import join
if l.rstrip() == "suspend":
log.info("suspending %d" % dominfo.id)
xd.domain_shutdown(dominfo.id, reason='suspend')
+ if dominfo.store_channel:
+ try:
+ dominfo.db.releaseDomain(dominfo.id)
+ except Exception, ex:
+ log.warning("error in domain release on xenstore: %s",
+ ex)
+ pass
dominfo.state_wait("suspended")
log.info("suspend %d done" % dominfo.id)
child.tochild.write("done\n")
if child.wait() != 0:
raise XendError("xc_save failed: %s" % lasterr)
+ if dominfo.store_channel:
+ dominfo.store_channel.close()
+ dominfo.db['store_channel'].delete()
+ dominfo.db.saveDB(save=True)
+ dominfo.store_channel = None
xd.domain_destroy(dominfo.id)
return None
raise XendError(
"not a valid guest state file: pfn count out of range")
+ if dominfo.store_channel:
+ evtchn = dominfo.store_channel.port2
+ else:
+ evtchn = 0
+
cmd = [PATH_XC_RESTORE, str(xc.handle()), str(fd),
- str(dominfo.id), str(nr_pfns)]
+ str(dominfo.id), str(nr_pfns), str(evtchn)]
log.info("[xc_restore] " + join(cmd))
child = xPopen3(cmd, True, -1, [fd, xc.handle()])
child.tochild.close()
lasterr = l.rstrip()
if fd == child.fromchild.fileno():
l = child.fromchild.readline()
- log.info(l.rstrip())
+ while l:
+ m = re.match(r"^(store-mfn) (\d+)\n$", l)
+ if m:
+ if dominfo.store_channel:
+ dominfo.store_mfn = int(m.group(2))
+ if dominfo.store_mfn >= 0:
+ dominfo.db.introduceDomain(dominfo.id,
+ dominfo.store_mfn,
+ dominfo.store_channel)
+ dominfo.exportToDB(save=True, sync=True))
+ log.info(l.rstrip())
+ try:
+ l = child.fromchild.readline()
+ except:
+ l = None
if filter(lambda (fd, event): event & select.POLLHUP, r):
break
int
main(int argc, char **argv)
{
- unsigned int xc_fd, io_fd, domid, nr_pfns;
+ unsigned int xc_fd, io_fd, domid, nr_pfns, evtchn;
+ int ret;
+ unsigned long mfn;
- if (argc != 5)
- errx(1, "usage: %s xcfd iofd domid nr_pfns", argv[0]);
+ if (argc != 6)
+ errx(1, "usage: %s xcfd iofd domid nr_pfns evtchn", argv[0]);
xc_fd = atoi(argv[1]);
io_fd = atoi(argv[2]);
domid = atoi(argv[3]);
nr_pfns = atoi(argv[4]);
+ evtchn = atoi(argv[5]);
- return xc_linux_restore(xc_fd, io_fd, domid, nr_pfns);
+ ret = xc_linux_restore(xc_fd, io_fd, domid, nr_pfns, evtchn, &mfn);
+ if (ret == 0) {
+ printf("store-mfn %li\n", mfn);
+ fflush(stdout);
+ }
+ return ret;
}